<template>
  <div ref="container" :class="['univer-sheet', { 'hidden-menu-more': config.showMenuList?.length }]"></div>
</template>

<script setup lang="ts">
import {
  type IWorkbookData,
  type IWorksheetData,
  type IRange,
  FUniver,
  Univer,
  UniverInstanceType,
  Workbook,
  LocaleType,
  LogLevel,
  defaultTheme,
  merge,
  createUniver
} from "@univerjs/presets";
import {
  type FWorkbook,
  type FWorksheet,
  UniverSheetsCorePreset,
  SetSelectionsOperation,
  RangeProtectionPermissionEditPoint,
  IContextMenuService,
  ComponentManager
} from "@univerjs/presets/preset-sheets-core";
import { UniverSheetsThreadCommentPreset } from "@univerjs/presets/preset-sheets-thread-comment";
import { UniverSheetsCrosshairHighlightPlugin } from "@univerjs/sheets-crosshair-highlight";
// 引入组件给国际化
import UniverPresetSheetsCoreZhCN from "@univerjs/presets/preset-sheets-core/locales/zh-CN";
import UniverSheetsThreadCommentZhCN from "@univerjs/presets/preset-sheets-thread-comment/locales/zh-CN";
import SheetsCrosshairHighlightZhCN from "@univerjs/sheets-crosshair-highlight/locale/zh-CN";
// 引入组件样式
import "@univerjs/presets/lib/styles/preset-sheets-core.css";
import "@univerjs/presets/lib/styles/preset-sheets-thread-comment.css";
import "@univerjs/sheets-crosshair-highlight/lib/index.css";

import "@univerjs/sheets-crosshair-highlight/facade";

// 重绘行号
import { rowHeaderCustomExtension } from "./plugin/rowHeaderCustomExtension";
// 自定义菜单插件
import { CustomMenuPlugin } from "./plugin/customMenuPlugin";
import { useUniverUtil } from "./hooks/useUniverUtil";
import popupMessage from "./components/popupMessage";

const props = defineProps({
  data: {
    type: Object as PropType<IWorkbookData>,
    default: () => ({} as IWorkbookData)
  },
  config: {
    type: Object as PropType<Record<string, any>>,
    default: () => {}
  }
});
const { data, config } = props;
const { hexToRgb, convertMenu, getHideMenuList } = useUniverUtil({});
let univerInstance: Univer | undefined = undefined;
let univerAPI = ref<FUniver | undefined>();
const workbook = ref<Workbook | undefined>();
const container = ref<HTMLElement | undefined>();
let defaultReadonlyRanges: Record<string, number>[] = [];
let readonlyRanges: Record<string, number>[] = [];

onMounted(() => init());
onBeforeUnmount(() => {
  destroyMutationObserver();
  destroyUniver();
});
/**
 * @description: 初始化
 * @return
 */
const init = () => {
  // 如果设置了标题行，标题默认只读
  if (config.headerRowCount) {
    defaultReadonlyRanges = [
      { startRow: 0, startColumn: 0, endRow: config.headerRowCount - 1, endColumn: config.maxColumnCount - 1, canMoveRow: 0 }
    ];
  }
  // 根据参数获取隐藏菜单
  const hiddenMenuList = getHideMenuList(config.showMenuList);
  // // 覆盖评论语言包
  // const commentLocales = {
  //   sheetThreadComment: {
  //     menu: {
  //       addComment: "添加备注"
  //     }
  //   },
  //   threadCommentUI: {
  //     editor: {
  //       placeholder: "备注",
  //       reply: "保存",
  //       cancel: "取消",
  //       save: "保存"
  //     }
  //   }
  // };
  // univer对象实例化
  const { univer } = createUniver({
    locale: LocaleType.ZH_CN,
    locales: {
      [LocaleType.ZH_CN]: merge({}, UniverPresetSheetsCoreZhCN, SheetsCrosshairHighlightZhCN, UniverSheetsThreadCommentZhCN)
    },
    theme: defaultTheme,
    logLevel: LogLevel.ERROR,
    presets: [
      UniverSheetsCorePreset({
        container: container.value,
        header: config.showHeader,
        footer: config.showFooter,
        toolbar: config.showToolbar,
        // toolbar: false,
        menu: hiddenMenuList,
        formulaBar: config.showFormula
      }),
      UniverSheetsThreadCommentPreset()
    ],
    plugins: [UniverSheetsCrosshairHighlightPlugin]
  });
  univerInstance = univer;
  univerAPI.value = FUniver.newAPI(univer);
  // 注册自定义菜单
  const { commands, menus } = convertMenu(config.customMenuData, univerAPI.value!);
  univer.registerPlugin(CustomMenuPlugin, { commands, menus, menuIcons: config.customMenuIcons });
  // 注册插件
  // 组件渲染后的生命周期
  univerAPI.value.addEvent(univerAPI.value.Event.LifeCycleChanged, ({ stage }) => {
    if (stage === 2) {
      const book = univerAPI.value?.getActiveWorkbook()!;
      const sheet = book.getActiveSheet();
      // 更改行号渲染
      const headerFontColor = hexToRgb(config.headerFontColor || "#000000");
      const headerBackgroundColor = hexToRgb(config.headerBackgroundColor || "#ffffff");
      univerAPI.value?.registerSheetRowHeaderExtension(
        book.getId()!,
        new rowHeaderCustomExtension(config.headerRowCount, config.showRowIndexEnd, headerFontColor, headerBackgroundColor)
      );
      // 注册自定义组件
      const componentManager = univerInstance?.__getInjector().get(ComponentManager);
      componentManager?.register("popupMessage", popupMessage, { framework: "vue3" });
      // 清空默认选区
      clearSelections(book, sheet);
      // 命令执行前拦截
      commandInterception(book, sheet);
      // 命令执行后触发
      commandTrigger(book, sheet);
      // 监听Univer右键子菜单弹窗，做边界判断，保证菜单可以显示完整
      // observerUniverSubmenuPopup();
    }
  });
  // 创建workbook实例
  workbook.value = univer.createUnit<IWorkbookData, Workbook>(UniverInstanceType.UNIVER_SHEET, data);
};

/**
 * @description: 清空选区
 * @param sheet
 * @param book
 * @return
 */
const clearSelections = (book: FWorkbook, sheet: FWorksheet) => {
  univerAPI.value?.executeCommand(SetSelectionsOperation.id, {
    selections: [],
    subUnitId: sheet.getSheetId(),
    unitId: book.getId(),
    type: 2
  });
};

/**
 * @description: 在执行命令前进行拦截
 * @param sheet
 * @param book
 */
const commandInterception = (book: FWorkbook, sheet: FWorksheet) => {
  // TODO univer新版本没有这个方法，先用旧的，后续更新版本后再换成新的
  // 监听单元格数据发生改变前
  sheet.onBeforeCellDataChange((cell) => {
    if (Object.keys(cell.getMatrix()).length) {
      const checkResult = config.onBeforeCellDataChange?.(cell.getDataRange(), cell.getMatrix());
      if (checkResult !== undefined && !checkResult) {
        throw new Error("业务检核未通过");
      } else if (checkResult) {
        return;
      }
      const { startRow, startColumn, endRow, endColumn } = cell.getDataRange();
      for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
        for (let columnIndex = startColumn; columnIndex <= endColumn; columnIndex++) {
          const isRedonly = readonlyRanges.find((readonlyRange) => {
            return (
              rowIndex >= readonlyRange.startRow &&
              rowIndex <= readonlyRange.endRow &&
              columnIndex >= readonlyRange.startColumn &&
              columnIndex <= readonlyRange.endColumn
            );
          });
          if (isRedonly) {
            // 拦截事件
            throw new Error("只读区域不允许操作");
          }
        }
      }
    }
  });
  univerAPI.value?.addEvent(univerAPI.value?.Event.BeforeCommandExecute, (command) => {
    const contextMenuService = univerInstance!.__getInjector().get(IContextMenuService);
    const reange = sheet.getActiveRange()?.getRange()!;
    // 先将右键菜单打开
    contextMenuService.enable();
    // 临时屏蔽 剪切、复制、粘贴 命令
    if (["univer.command.copy", "univer.command.cut", "sheet.command.paste-by-short-key"].includes(command.id)) {
      throw new Error("暂时禁止复制、粘贴、剪切");
    }
    // 单元格获取焦点
    if (command.id === "sheet.operation.set-activate-cell-edit") {
      if (readonlyRanges.length) {
        const isRedonly = readonlyRanges.find((readonlyRange) => {
          // reange.rangeType=1时为整行选择
          return (
            (reange.rangeType !== 1 || !readonlyRange.canMoveRow) &&
            reange.startRow >= readonlyRange.startRow &&
            reange.startRow <= readonlyRange.endRow &&
            reange.endRow >= readonlyRange.startRow &&
            reange.endRow <= readonlyRange.endRow &&
            reange.startColumn >= readonlyRange.startColumn &&
            reange.startColumn <= readonlyRange.endColumn &&
            reange.endColumn >= readonlyRange.startColumn &&
            reange.endColumn <= readonlyRange.endColumn
          );
        });
        if (isRedonly) {
          // 禁止右键菜单
          contextMenuService.hideContextMenu();
          contextMenuService.disable();
          // 清空选区
          clearSelections(book, sheet);
          // 拦截事件
          throw new Error("只读区域禁止任何操作");
        }
      }
    }
    // 禁止编辑单元格
    if (command.id === "sheet.operation.set-cell-edit-visible") {
      throw new Error("禁止编辑");
    }
    // 监听键盘录入
    if (["doc.command.ime-input", "doc.command.insert-text"].includes(command.id)) {
      throw new Error("禁止使用键盘录入");
    }
    // 禁止调整行高
    if (command.id === "sheet.command.delta-row-height") {
      throw new Error("禁止调整行高");
    }
    // 禁止异动单元格
    if (command.id === "sheet.command.move-range") {
      throw new Error("禁止移动单元格");
    }
    // 监听缩放
    if (["sheet.command.set-zoom-ratio", "sheet.operation.set-zoom-ratio"].includes(command.id)) {
      throw new Error("禁止缩放");
    }
    // 监听新增列
    if (command.id === "sheet.mutation.insert-col") {
      console.log(command, sheet?.getMaxColumns(), config.maxColumnCount);
      if (sheet?.getMaxColumns() + command.params.colInfo.length > config.maxColumnCount) {
        showMessage("error", `新增列失败，已达到最大列数：${config.maxColumnCount}`);
        throw new Error("超出设置的最大列数，禁止新增列");
      }
    }
  });
};

/**
 * @description: 命令执行后触发
 * @param sheet
 * @param book
 */
const commandTrigger = (book: FWorkbook, sheet: FWorksheet) => {
  univerAPI.value?.addEvent(univerAPI.value?.Event.CellHover, (cell: any) => {
    const { row: rowIndex, col: columnIndex } = cell;
    config.onCellHover?.(rowIndex, columnIndex);
  });
  // TODO univer新版本没有这个方法，先用旧的，后续更新版本后再换成新的
  // 监听单元格数据发生改变
  sheet.onCellDataChange((cell) => {
    if (Object.keys(cell.getMatrix()).length) {
      config.onCellDataChange?.(cell.getDataRange(), cell.getMatrix());
    }
  });
  // 监听各种命令执行后
  univerAPI.value?.addEvent(univerAPI.value?.Event.CommandExecuted, (command: any) => {
    nextTick(() => {
      // 监听删除和插入列
      if (["sheet.mutation.remove-col", "sheet.mutation.insert-col", "sheet.command.move-cols"].includes(command.id)) {
        if (command.id == "sheet.mutation.insert-col") {
          const range = command.params.range;
          const insertRange = sheet.getRange(config.headerRowCount, range.startColumn, range.endRow + 1 + config.headerRowCount, 1);
          insertRange.setValue({ s: { bg: { rgb: "#ffffff" } }, v: "" });
        }
        config.onColumnChange?.();
      }
      // 监听插入行
      if (command.id === "sheet.mutation.insert-row") {
        const range = command.params.range;
        const insertRange = sheet.getRange(range.startRow, range.startColumn, 1, range.endColumn + 1);
        insertRange.setValue({ s: { bg: { rgb: "#ffffff" } }, v: "" });
      }
      // 监听清除选取内容
      if (command.id === "sheet.command.clear-selection-content") {
        config.onClearCell?.(sheet);
      }
      // 行顺序调整改变
      if (command.id === "sheet.command.move-rows") {
        // 回传新行号和旧的开始行号和结束行号
        config.onMoveRows?.(command.params.toRange.startRow, command.params.fromRange.startRow, command.params.fromRange.endRow);
      }
    });
  });
};

/**
 * @description: 设置只读区域
 * @param ranges
 * @param clearFlag
 * @return
 */
const setReadonlyRanges = async (ranges: Record<string, number>[], clearFlag?: boolean) => {
  if (clearFlag) {
    readonlyRanges = defaultReadonlyRanges;
  }
  // 合并去重
  const set = new Set([...readonlyRanges, ...ranges].map((item) => JSON.stringify(item)));
  readonlyRanges = Array.from(set).map((item) => JSON.parse(item));
};

/**
 * @description:  修复滚动条遮挡数据
 * @return
 */
const fixScrollBarPressData = async () => {
  const sheet = univerAPI.value?.getActiveWorkbook()?.getActiveSheet()!;
  // 这将在第一行位置后插入一行
  sheet.insertRowAfter(sheet.getMaxRows());
  const startRow = sheet.getMaxRows() - 1;
  sheet.setRowHeightsForced(startRow, 1, 20);
  const newRow = {
    startRow: startRow,
    startColumn: 0,
    endRow: startRow,
    endColumn: config.maxColumnCount - 1,
    canMoveRow: 0
  };
  // 设置只读
  setReadonlyRanges([newRow]);
};

/**
 * @description: 设置保护区域
 * @param ranges 指定区域
 * @param flag true保护，false取消保护
 * @return
 */
const setPermissionRanges = async (ranges: IRange[], flag: boolean) => {
  // const book = univerAPI.value?.getActiveWorkbook();
  // const sheet = book?.getActiveSheet();
  // const permission = univerAPI.value?.getPermission();
  // const res = await permission?.addRangeBaseProtection(book?.getId()!, sheet?.getSheetId()!, ranges);
  // const { permissionId, ruleId } = res!;
  // if (flag) {
  //   permission?.setRangeProtectionPermissionPoint(
  //     book?.getId()!,
  //     sheet?.getSheetId()!,
  //     permissionId,
  //     RangeProtectionPermissionEditPoint,
  //     false
  //   );
  //   // 隐藏保护提示弹窗
  //   permission?.setPermissionDialogVisible(false);
  // } else {
  //   permission?.removeRangeProtection(book?.getId()!, sheet?.getSheetId()!, [ruleId]);
  // }
};

/**
 * @description: 获取数据
 */
const getData = (): IWorkbookData => {
  if (!workbook.value) {
    throw new Error("表格尚未初始化");
  }
  return workbook.value.save();
};
/**
 * @description: 获取单元格数据集合
 * @param sheetName 工作表名称，不传则返回第一个工作表的单元格数据
 * @return
 */
const getSheetData = (sheetName?: string) => {
  const tableData = getData();
  let sheet: Partial<IWorksheetData> = {};
  if (sheetName) {
    sheet = tableData.sheets[sheetName];
  } else {
    sheet = Object.values(tableData.sheets)[0];
  }
  if (!sheet) {
    return undefined;
  }
  return { cellDatas: sheet.cellData, rowCount: sheet.rowCount, columnCount: sheet.columnCount };
};
let popupDisposeable: any = undefined;
let popupCell: string | undefined = undefined;
/**
 * @description: 显示提示信息
 * @param rowIndex
 * @param columnIndex
 * @param message
 * @return
 */
const showPopupMessage = (rowIndex: number, columnIndex: number, message: string) => {
  const key = `row${rowIndex}-column${columnIndex}`;
  // 如果key相同 且已经显示 直接返回，防止提示框画面闪烁
  if (popupDisposeable && popupCell === key) {
    return;
  }
  popupCell = key;
  const sheet = univerAPI.value?.getActiveWorkbook()?.getActiveSheet();
  // 先销毁在创建
  hiddenPopupMessage();
  popupDisposeable = sheet?.getRange(rowIndex, columnIndex, 1, 1).attachPopup({
    // componentKey 必须是一个组件或已注册组件的键
    componentKey: "popupMessage",
    //这是组件的数据，可以传递给组件
    extraProps: {
      message
    }
  });
};
/**
 * @description: 隐藏提示信息
 */
const hiddenPopupMessage = () => {
  popupDisposeable && popupDisposeable.dispose();
  popupDisposeable = undefined;
};
/**
 * @description: 设置十字高亮
 * @param color 高亮颜色，不传则关闭十字高亮
 * @return
 */
const setCrosshairHighlightColor = (color?: string, opacity?: number) => {
  if (color) {
    let rgbColor: string = color;
    // 如果传入的颜色是16进制，需要转换
    if (!color.includes("rgba")) {
      const rgbArr = hexToRgb(color);
      if (rgbArr?.length === 3) {
        rgbColor = `rgba(${rgbArr.join(",")},${opacity || 1})`;
      }
    }
    univerAPI.value?.setCrosshairHighlightEnabled(true);
    univerAPI.value?.setCrosshairHighlightColor(rgbColor);
  } else {
    univerAPI.value?.setCrosshairHighlightEnabled(false);
  }
};
let mutationObserverInstance: MutationObserver | undefined = undefined;
/**
 * @description: 监听Univer右键子菜单弹窗，做边界判断，保证菜单可以显示完整
 */
const observerUniverSubmenuPopup = () => {
  // 定义MutationObserver回调方法
  const observerCallBack = (mutations: any) => {
    const submenuSelector = ".univer-menu-submenu-popup:not(.univer-menu-submenu-hidden)";
    const elements: NodeListOf<Element> = document.querySelectorAll(submenuSelector);
    if (elements.length > 0) {
      elements.forEach((element) => {
        const height = (element as HTMLElement).clientHeight;
        const topPx = (element as HTMLElement).style.top;
        // top中带px单位的弹窗才处理
        if (height && topPx?.includes("px")) {
          // 通过类型转换去除末尾的px
          const top = parseInt(topPx);
          const pageHeight = document.body.clientHeight;
          let newTop = `${top}px`;
          // 根据弹窗高度和弹窗top位置，如超出屏幕，矫正top位置
          if (top < 0) {
            newTop = "20px";
          } else if (top + height > pageHeight) {
            newTop = `${pageHeight - height}px`;
          }
          (element as HTMLElement).style.top = newTop;
        }
      });
    }
  };
  const observerNode = document.querySelector(".univer-theme:not(.univer-sheet)");
  if (observerNode) {
    // 实例化MutationObserver
    mutationObserverInstance = new MutationObserver(observerCallBack);
    // 调用observe()观察整个univer-theme节点
    mutationObserverInstance.observe(observerNode, {
      // 观察属性的变化,
      attributes: true,
      // 观察子组件变化
      childList: true
    });
  }
};
/**
 * @description: 销毁MutationObserver对象
 */
const destroyMutationObserver = () => {
  mutationObserverInstance?.disconnect();
  mutationObserverInstance = undefined;
};
/**
 * @description: 销毁Univer对象
 */
const destroyUniver = () => {
  univerInstance?.dispose();
  univerInstance = undefined;
  workbook.value = undefined;
};
/**
 * @description: 向父组件暴漏方法
 */
defineExpose({
  univerAPI,
  setReadonlyRanges,
  fixScrollBarPressData,
  setPermissionRanges,
  getData,
  getSheetData,
  showPopupMessage,
  setCrosshairHighlightColor,
  hiddenPopupMessage,
  destroyUniver
});
</script>

<style lang="scss">
.univer-sheet {
  width: 100%;
  height: 100%;
  overflow: hidden;
  // .univer-workbench-container-header {
  //   .univer-text-base {
  //     background-color: #f5f5f5;
  //     font-size: 16px !important;
  //     line-height: 16px !important;
  //   }
  //   .univer-h-8 {
  //     height: 32px;
  //   }
  //   .univer-h-6 {
  //     height: 24px;
  //   }
  //   .univer-px-4 {
  //     padding-left: 16px;
  //     padding-right: 16px;
  //   }
  //   .univer-gap-2 {
  //     gap: 8px;
  //   }
  // }
  // 隐藏更多选项
  // &.hidden-menu-more {
  //  .univer-toolbar-btn .univerjs-icon-more-function-single {
  //     display: none;
  //  }
  // }
  // 顶部工具栏背景
  // .univer-toolbar {
  //   background-color: #f5f5f5;
  //   .menu-icon {
  //     margin: 5px -5px 0 0;
  //   }
  // }
  // .univer-toolbar-container {
  //   width: 100%;
  //   margin: 0 40px;
  //   justify-content: left;
  // }
  // 隐藏 拖动后显示的图标
  // .univer-btn-container {
  //   display: none;
  // }
}
:global(.univer-menubar) {
  display: none;
}
// 降低el-dialog组件的z-index，保证univer组件的浮窗可以正常显示
.el-overlay {
  z-index: 1000 !important;
}
.univer-theme {
  .univer-thread-comment {
    padding: 12px;
    background-color: black;
    * {
      color: #f5f5f5;
    }
    .univer-thread-comment-title {
      display: none;
    }
    .univer-thread-comment-content .univer-thread-comment-item {
      padding: 0 6px;
      margin-bottom: 0;
      .univer-thread-comment-item-head,
      .univer-thread-comment-item-title,
      .univer-thread-comment-item-time {
        display: none;
      }
      .univer-thread-comment-item-title {
        position: absolute;
        right: 5px;
        .univer-thread-comment-username {
          display: none;
        }
        .univer-thread-comment-icon {
          font-size: 16px;
          &:first-child {
            display: none;
          }
        }
      }
      .univer-thread-comment-item-content {
        font-size: 14px;
        letter-spacing: 2px;
      }
    }
    .univer-rich-text-editor-wrap {
      display: none;
    }
  }
  // 右键菜单样式
  //.univer-menu-item-content {
  //  gap: 0;
  //  svg {
  //    margin-right: 8px;
  //  }
  //  .menu-icon {
  //    display: none;
  //  }
  //}
}
</style>
